package com.kl.util;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 根据 java 类自动生成sql 语句 - mysql
 */
public class SqlGenerator {

    private static final Map<Object, Object> javaProperty2SqlColumnMap = new HashMap<>();
    private static final Logger logger = LoggerFactory.getLogger(SqlGenerator.class);

    // 初始化JAVA实体中的属性类型和数据库中字段数据类型的对应关系
    static {
        javaProperty2SqlColumnMap.put("Integer", "int");
        javaProperty2SqlColumnMap.put("Short", "tinyint(4)");
        javaProperty2SqlColumnMap.put("Long", "bigint");
        javaProperty2SqlColumnMap.put("BigDecimal", "decimal(19,2)");
        javaProperty2SqlColumnMap.put("Double", "double precision not null");
        javaProperty2SqlColumnMap.put("Float", "float");
        javaProperty2SqlColumnMap.put("boolean", "bit(1)");
        javaProperty2SqlColumnMap.put("Timestamp", "datetime");
        javaProperty2SqlColumnMap.put("Date", "datetime");
        javaProperty2SqlColumnMap.put("LocalDateTime", "timestamp");
        javaProperty2SqlColumnMap.put("String", "varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL");
    }

    /**
     * 根据实体类生成建表语句
     *
     * @param className 全限定类名
     * @param tableName 生成的表名
     * @return 建表语句
     */
    public static String generateSql(String className, String tableName) {
        try {
            Class<?> clz = Class.forName(className);
            String param;   //类中的属性
            String column;  //数据库字段
            StringBuilder sql;
            sql = new StringBuilder(50);
            // 如果不指定表名则默认使用类名作为表名
            if (tableName == null || ("").equals(tableName)) {
                tableName = clz.getSimpleName();
            }

            // 建表语句开头: 默认格式，如果表存在则删除,然后再建表
            sql.append("\n\n/*========= ").append(tableName).append(" ==========*/\n");
            sql.append("DROP TABLE IF EXISTS `").append(tableName).append("`; \n");
            sql.append("CREATE TABLE `").append(tableName).append("` ( \n");

            String keyField = null;
            Field[] fields = clz.getDeclaredFields(); //获取类中的所有属性
            for (Field f : fields) {
                // 获取类属性的名字,如id、name
                column = f.getName();
                if (("serialVersionUID").equals(column)) {
                    continue;
                }
                // 获取类参数的类型名，如Integer、Long
                param = f.getType().getSimpleName();

                // 将类参数大写字母转小写，并添加下划线
                for (int i = 0; i < column.length(); i++) {
                    char c = column.charAt(i);
                    if (Character.isUpperCase(c) && i > 0) {
                        column = column.replaceAll(
                                Character.toString(c), "_" + Character.toLowerCase(c));
                    }
                }
                sql.append("`").append(column).append("`");
                // 获取与JAVA类型对应的数据库类型
                sql.append(" ").append(javaProperty2SqlColumnMap.get(param));
                sql.append(" ").append("DEFAULT NULL").append(" ").append("COMMENT").append(" ").append("'").append(column).append("'");
                //默认第一个是主键
                if (keyField == null) {
                    keyField = column;
                }
                sql.append(",\n");
            }
            sql.append("PRIMARY KEY (`").append(keyField).append("`) USING BTREE,");
            sql.append("\nINDEX `").append(keyField).append("`(`").append(keyField).append("`) USING BTREE ) ");
            sql.append("\nENGINE = INNODB DEFAULT CHARSET= utf8mb4;");

            return sql.toString();

        } catch (ClassNotFoundException e) {
            logger.debug("该类未找到！");
            return null;
        }
    }

    /**
     * 获取包下的所有类名称,获取的结果类似于 XXX.java
     */
    public static List<String> getAllClasses(String packageName) {
        List<String> classList = new ArrayList<>();
        String className;
        File f = new File(packageName);
        if (f.exists() && f.isDirectory()) {
            File[] files = f.listFiles();
            assert files != null;
            for (File file : files) {
                className = file.getName();
                classList.add(className);
            }
            return classList;
        } else {
            logger.debug("包路径未找到！");
            return null;
        }
    }

    /**
     * 将string 写入sql文件
     *
     * @param str  sql语句
     * @param path 输出的文件路径
     */
    public static void StringToSql(String str, String path) {
        byte[] sourceByte = str.getBytes();
        try {
            //文件路径（路径+文件名）
            File file = new File(path);
            //文件不存在则创建文件，先创建目录
            if (!file.exists()) {
                File dir = new File(file.getParent());
                dir.mkdirs();
                file.createNewFile();
            }
            //文件输出流用于将数据写入文件
            FileOutputStream outStream = new FileOutputStream(file);
            outStream.write(sourceByte);
            outStream.flush();
            outStream.close();
            logger.info("输出成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}